# -*- coding: utf-8 -*-
from PyQt5.QtCore import (QFileInfo, QSize, QPoint, QRect, QSettings, QSize, Qt, QUrl, QTimer, QRegExp, QThread, pyqtSignal)
from PyQt5.QtWidgets import (QAction, QAbstractItemView, QDialog, QFileDialog, QWidget, QFrame, QHBoxLayout, QLabel, QLineEdit, QListView, 
    QMenu, QPushButton, QDialogButtonBox, QSlider, QTableWidget, QTableWidgetItem, QVBoxLayout, QGridLayout, QFormLayout, QListWidget, 
    QListWidgetItem, QTabWidget, QApplication, QComboBox, QHeaderView, QScrollBar, QMessageBox, QProgressBar, QTextBrowser, QCheckBox, QCompleter)
from PyQt5.QtGui import (QBrush, QColor, QCursor, QPixmap, QFont, QPainter, QPen, QLinearGradient, QRegExpValidator,
    QStandardItemModel, QStandardItem, QMouseEvent, QIcon, QMovie)
from PyQt5.QtWebEngineWidgets import (QWebEnginePage, QWebEngineView)
import requests
import shutil, os
import time
import json
import re

def show_text(function):
    def wrapped(self, *args, **kwargs):
        if self.vars["showTextLock"]:
            self.vars["showTextLock"] = False
            result = function(self, *args, **kwargs)
            items = self.get_selected()
            l = len(items)
            l_ = self.vars["listViewModel"].rowCount() - 1
            self.vars["listViewModel"].item(0).setCheckState(
                Qt.Checked if l == l_ else Qt.Unchecked if l == 0 else Qt.PartiallyChecked)
            self.vars["lineEdit"].setText(
                "(全选)" if l == l_ else "(无选择)" if l == 0 else ";".join((item.text() for item in items)))
            self.vars["showTextLock"] = True
        else:
            result = function(self, *args, **kwargs)
        return result
 
    return wrapped


class QComboCheckBox(QComboBox):
    class MyListView(QListView):
        def __init__(self, parent: QWidget = None, vars=None):
            super().__init__(parent)
            self.vars = vars
 
        def mousePressEvent(self, event: QMouseEvent):
            self.vars["lock"] = False
            super().mousePressEvent(event)
 
        def mouseDoubleClickEvent(self, event: QMouseEvent):
            self.vars["lock"] = False
            super().mouseDoubleClickEvent(event)
 
    def __init__(self, parent: QWidget = None):
        super().__init__(parent)
        self.vars = dict()
        self.vars["lock"] = True
        self.vars["showTextLock"] = True
        # 装饰器锁，避免批量操作时重复改变lineEdit的显示
        self.vars["lineEdit"] = QLineEdit(self)
        self.vars["lineEdit"].setReadOnly(True)
        self.vars["listView"] = self.MyListView(self, self.vars)
        self.vars["listViewModel"] = QStandardItemModel(self)
        self.setModel(self.vars["listViewModel"])
        self.setView(self.vars["listView"])
        self.setLineEdit(self.vars["lineEdit"])
 
        self.activated.connect(self.__show_selected)
 
        self.add_item(0, "(全选)")
 
    def count(self):
        # 返回子项数
        return super().count() - 1
 
    @show_text
    def add_item(self, value: "int" = 0, text: "str" = ""):
        # 根据文本添加子项
        item = QStandardItem(value)
        item.setData(value, Qt.UserRole + 1)
        item.setText(text)
        item.setCheckable(True)
        item.setCheckState(Qt.Checked)
        self.vars["listViewModel"].appendRow(item)
 
    @show_text
    def add_items(self, items: "list"):
        # 根据文本列表添加子项
        for it in items:
            self.add_item(it[0], str(it[1]))
 
    @show_text
    def clear_items(self):
        # 清空所有子项
        self.vars["listViewModel"].clear()
        self.add_item(0, "(全选)")
 
    def find_index(self, index: "int"):
        # 根据索引查找子项
        return self.vars["listViewModel"].item(index if index < 0 else index + 1)
 
    def find_indexs(self, indexs: "tuple or list"):
        # 根据索引列表查找子项
        return [self.find_index(index) for index in indexs]
 
    def find_text(self, text: "str"):
        # 根据文本查找子项
        tempList = self.vars["listViewModel"].findItems(text)
        tempList.pop(0) if tempList and tempList[0].row() == 0 else tempList
        return tempList
 
    def find_texts(self, texts: "tuple or list"):
        # 根据文本列表查找子项
        return {text: self.find_text(text) for text in texts}
 
    def get_text(self, index: "int"):
        # 根据索引返回文本
        return self.vars["listViewModel"].item(index if index < 0 else index + 1).text()
 
    def get_texts(self, indexs: "tuple or list"):
        # 根据索引列表返回文本
        return [self.get_text(index) for index in indexs]
 
    def change_text(self, index: "int", text: "str"):
        # 根据索引改变某一子项的文本
        self.vars["listViewModel"].item(index if index < 0 else index + 1).setText(text)
 
    @show_text
    def select_index(self, index: "int", state: "bool" = True):
        # 根据索引选中子项，state=False时为取消选中
        self.vars["listViewModel"].item(index if index < 0 else index + 1).setCheckState(
            Qt.Checked if state else Qt.Unchecked)
 
    @show_text
    def select_indexs(self, indexs: "tuple or list", state: "bool" = True):
        # 根据索引列表选中子项，state=False时为取消选中
        for index in indexs:
            self.select_index(index, state)
 
    @show_text
    def select_text(self, text: "str", state: "bool" = True):
        # 根据文本选中子项，state=False时为取消选中
        for item in self.find_text(text):
            item.setCheckState(Qt.Checked if state else Qt.Unchecked)
 
    @show_text
    def select_texts(self, texts: "tuple or list", state: "bool" = True):
        # 根据文本列表选中子项，state=False时为取消选中
        for text in texts:
            self.select_text(text, state)
 
    @show_text
    def select_reverse(self):
        # 反转选择
        if self.vars["listViewModel"].item(0).checkState() == Qt.Unchecked:
            self.select_all()
        elif self.vars["listViewModel"].item(0).checkState() == Qt.Checked:
            self.select_clear()
        else:
            for row in range(1, self.vars["listViewModel"].rowCount()):
                self.__select_reverse(row)
 
    def __select_reverse(self, row: "int"):
        item = self.vars["listViewModel"].item(row)
        item.setCheckState(Qt.Unchecked if item.checkState() == Qt.Checked else Qt.Checked)
 
    @show_text
    def select_all(self):
        # 全选
        for row in range(0, self.vars["listViewModel"].rowCount()):
            self.vars["listViewModel"].item(row).setCheckState(Qt.Checked)
 
    @show_text
    def select_clear(self):
        # 全不选
        for row in range(0, self.vars["listViewModel"].rowCount()):
            self.vars["listViewModel"].item(row).setCheckState(Qt.Unchecked)
 
    @show_text
    def remove_index(self, index: "int"):
        # 根据索引移除子项
        return self.vars["listViewModel"].takeRow(index if index < 0 else index + 1)
 
    @show_text
    def remove_indexs(self, indexs: "tuple or list"):
        # 根据索引列表移除子项
        return [self.remove_index(index) for index in sorted(indexs, reverse=True)]
 
    @show_text
    def remove_text(self, text: "str"):
        # 根据文本移除子项
        items = self.find_text(text)
        indexs = [item.row() for item in items]
        return [self.vars["listViewModel"].takeRow(index) for index in sorted(indexs, reverse=True)]
 
    @show_text
    def remove_texts(self, texts: "tuple or list"):
        # 根据文本列表移除子项
        return {text: self.remove_text(text) for text in texts}
 
    def get_selected(self):
        # 获取当前选择的子项
        items = list()
        for row in range(1, self.vars["listViewModel"].rowCount()):
            item = self.vars["listViewModel"].item(row)
            if item.checkState() == Qt.Checked:
                items.append(item)
        return items

    def get_selected_vals(self):
        # 获取当前选择子项的值
        items = self.get_selected()
        return [it.data() for it in items]
 
    def is_all(self):
        # 判断是否是全选
        return True if self.vars["listViewModel"].item(0).checkState() == Qt.Checked else False
 
    def sort(self, order=Qt.AscendingOrder):
        # 排序，默认正序
        self.vars["listViewModel"].sort(0, order)
 
    @show_text
    def __show_selected(self, index):
        if not self.vars["lock"]:
            if index == 0:
                if self.vars["listViewModel"].item(0).checkState() == Qt.Checked:
                    self.select_clear()
                else:
                    self.select_all()
            else:
                self.__select_reverse(index)
 
            self.vars["lock"] = True
 
    def hidePopup(self):
        if self.vars["lock"]:
            super().hidePopup()

class MyLineEdit(QLineEdit):
    clicked = pyqtSignal()
    def __init__(self, parent=None):
        super(MyLineEdit, self).__init__()

    def mouseReleaseEvent(self, QMouseEvent):
        if QMouseEvent.button()==Qt.LeftButton:
            self.clicked.emit()

class _importvideoDialog(QWidget):
    def __init__(self, parent=None):
        super(_importvideoDialog, self).__init__()
        # 已选择文件列表
        self.filepaths = []
        # 已选择用户列表
        self.userids   = []
        self.parent = parent
        self.setLayouts()

    def setLayouts(self):
        userWidget = QWidget()
        gridWidget = QVBoxLayout()
        self.phoneLabel = QLabel('第一步，请选择为哪些抖音号导入待发布视频')
        self.userscombo = QComboCheckBox()
        self.userscombo.setStyleSheet('QComboBox{ width:120px; padding:2px; margin-top:20px;} QStandardItem{ line-height:150%; }')
        
        gHlayout = QHBoxLayout()
        gHlayout.setSpacing(0)
        self.filesEdit = MyLineEdit()
        self.filesEdit.setReadOnly(True)
        self.filesEdit.setStyleSheet('QLineEdit{padding:3px; margin-top:20px;}')
        #self.filesEdit.clicked.connect(self.selectFiles)
        self.filesEdit.hide()
        gHlayout.addWidget(self.filesEdit)

        self.btnSelect = QPushButton()
        self.btnSelect.setText('浏览..')
        self.btnSelect.setStyleSheet('QPushButton{margin-top:19px; width:50px; height:22px;}')
        self.btnSelect.clicked.connect(self.selectFiles)
        self.btnSelect.hide()
        
        gHlayout.addWidget(self.btnSelect)

        gridWidget.addWidget(self.phoneLabel)
        gridWidget.addWidget(self.userscombo)
        gridWidget.addLayout(gHlayout)
        gridWidget.addStretch(1)
        userWidget.setLayout(gridWidget)

        self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        self.buttonBox.button(QDialogButtonBox.Ok).setText('下一步')
        self.buttonBox.button(QDialogButtonBox.Cancel).setText('取消')
        self.buttonBox.accepted.connect(self.accept)
        self.buttonBox.rejected.connect(self.reject)

        mainLayout = QVBoxLayout()
        mainLayout.addWidget(userWidget)
        mainLayout.addWidget(self.buttonBox)
        self.setLayout(mainLayout)
        self.setWindowTitle('导入视频文件到待发布区')
        self.setWindowModality(Qt.ApplicationModal)
        self.setWindowFlags(Qt.WindowCloseButtonHint)

    def addComboItem(self, items):
        self.userscombo.add_items(items)
        self.userscombo.select_clear()

    def selectFiles(self):
        files, _ = QFileDialog.getOpenFileNames(self, '选择视频文件', '', '视频文件 (*.mp4)')
        if files:
            self.filepaths = files
            select_pathnum = len(self.filepaths)
            select_pathstr = ';'.join(self.filepaths) if select_pathnum < 2 else ('...;%s' % self.filepaths[int(select_pathnum-1)])
            self.filesEdit.setText(select_pathstr + (' 已选择[%s]个文件' % select_pathnum))
            self.buttonBox.setEnabled(True)

    def accept(self):
        # 选择文件后调用导入
        if len(self.filepaths) > 0:
            self.filesEdit.setEnabled(False)
            self.btnSelect.setEnabled(False)
            self.buttonBox.button(QDialogButtonBox.Ok).setText('正在导入..')
            self.buttonBox.setEnabled(False)
            self.parent.importVideos(self.userids, self.filepaths)

        else:
            # 选择账号后进入第二步
            self.userids = self.userscombo.get_selected_vals()
            if len(self.userids) > 0:
                self.phoneLabel.setText('第二步，请选择导入哪些文件到待发布区')
                self.buttonBox.button(QDialogButtonBox.Ok).setText('导 入')
                self.buttonBox.setEnabled(False)
                self.userscombo.hide()
                self.filesEdit.show()
                self.btnSelect.show()

    def reject(self):
        self.close()

class _newuserDialog(QWidget):
    def __init__(self, parent=None):
        super().__init__()
        self.parent = parent
        self.setLayouts()

    def setLayouts(self):
        userWidget = QWidget()
        gridWidget = QVBoxLayout()
        self.phoneLabel = QLabel('第一步，请输入要添加的抖音账号(手机号)')
        self.phoneEdit = QLineEdit()
        self.phoneEdit.setMaxLength(11)
        self.phoneEdit.setStyleSheet('QLineEdit{font-size:14px; padding:3px; margin-top:20px;}')

        #设置文本允许出现的字符内容
        reg=QRegExp('[a-zA-Z0-9]+$')
        #自定义文本验证器
        pValidator=QRegExpValidator(self)
        #设置属性
        pValidator.setRegExp(reg)
        self.phoneEdit.setValidator(pValidator)

        gridWidget.addWidget(self.phoneLabel)
        gridWidget.addWidget(self.phoneEdit)
        gridWidget.addStretch(1)
        userWidget.setLayout(gridWidget)

        self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        self.buttonBox.button(QDialogButtonBox.Ok).setText('下一步')
        self.buttonBox.button(QDialogButtonBox.Cancel).setText('取消')
        self.buttonBox.accepted.connect(self.accept)
        self.buttonBox.rejected.connect(self.reject)

        mainLayout = QVBoxLayout()
        mainLayout.addWidget(userWidget)
        mainLayout.addWidget(self.buttonBox)
        self.setLayout(mainLayout)
        self.setWindowTitle('添加快手号')
        self.setWindowModality(Qt.ApplicationModal)
        self.setWindowFlags(Qt.WindowCloseButtonHint)

    def accept(self):
        phone = self.phoneEdit.text()
        if len(phone) > 5:
            self.phoneLabel.setText('第二步，打开抖音客户端扫二维码登录')
            self.buttonBox.setEnabled(False)
            self.phoneEdit.hide()
            self.parent.usersAdd(phone=phone)

    def reject(self):
        self.close()

class _settingsDialog(QWidget):
    def __init__(self, parent=None):
        super().__init__()
        self.parent = parent
        self.setLayouts()
        self.setWindowTitle('设置')
        self.setWindowModality(Qt.ApplicationModal)
        self.setWindowFlags(Qt.WindowCloseButtonHint)

    def accept(self):
        self.parent.pub_tmee = re.sub('\D', '', self.timeCob.currentText())
        self.parent.pub_grid = 1 if self.gridChk.isChecked() else 0
        self.parent.pub_city = ''.join(re.findall(r'[\u4e00-\u9fa5]', self.cityCob.currentText()))
        self.parent.pub_dist = re.sub('\D', '', self.distCob.currentText())
        self.close()

    def reject(self):
        self.close()

    def setLayouts(self):
        
        self.timeCob = QComboBox()
        for i in range(1, 100):
            self.timeCob.addItem('%s秒' % i)
        self.timeCob.setCurrentIndex(int(self.parent.pub_tmee) - 1)

        self.cityCob = QComboBox()
        self.cityCob.setFocusPolicy(Qt.StrongFocus)
        #self.cityCob.setEditable(True)
        self.cityCob.addItem('')
        citys = []
        jude = 0
        with open(os.path.join(self.parent.absolutePath, 'data', 'citys.json'), 'r') as f:
            self.citys = json.load(f)
            for pv in self.citys['provinces']:
                jude += 1
                self.cityCob.addItem('======' + pv['provinceName'] + '======')
                if pv['provinceName'] == self.parent.pub_city:
                    self.cityCob.setCurrentIndex(jude)
                for ct in pv['citys']:
                    jude += 1
                    citys.append(ct['citysName'])
                    self.cityCob.addItem(ct['citysName'])
                    if ct['citysName'] == self.parent.pub_city:
                        self.cityCob.setCurrentIndex(jude)

        #completer = QCompleter(citys)
        #completer.setFilterMode(Qt.MatchContains)
        #self.cityCob.setCompleter(completer)

        self.gridChk = QCheckBox('启用')
        if self.parent.pub_grid == 1:
            self.gridChk.setCheckState(Qt.Checked)

        self.distCob = QComboBox()
        for i in range(1, 100):
            self.distCob.addItem('%s公里' % i)
        #self.distCob.setEditable(True)
        #completer2 = QCompleter([str('%s公里'%i) for i in range(1, 30)])
        #self.distCob.setCompleter(completer2)
        self.distCob.setCurrentIndex(int(self.parent.pub_dist) - 1)
        
        layout = QFormLayout()
        layout.addRow('上传间隔时间', self.timeCob)
        layout.addRow('发布定位城市', self.cityCob)
        layout.addRow('基于栅格发布', self.gridChk)
        layout.addRow('栅格间距', self.distCob)
        layout.setSpacing(10)
        layout.setLabelAlignment(Qt.AlignRight)

        self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        self.buttonBox.button(QDialogButtonBox.Ok).setText('保存')
        self.buttonBox.button(QDialogButtonBox.Cancel).setText('取消')
        self.buttonBox.accepted.connect(self.accept)
        self.buttonBox.rejected.connect(self.reject)

        mainLayout = QVBoxLayout()
        mainLayout.addLayout(layout)
        mainLayout.addWidget(self.buttonBox)
        self.setLayout(mainLayout)


class _webViewFrame(QFrame):
    def __init__(self, parent=None):
        super(_webViewFrame, self).__init__()
        self.parent = parent
        self.setParent(self.parent)
        self.setLayouts()

    def setLayouts(self):
        self.webview = QWebEngineView()
        self.mainLayout = QVBoxLayout()
        self.mainLayout.addWidget(self.webview)
        self.setLayout(self.mainLayout)

    def load(self, url):
        self.webview.load(QUrl(url))

class _videoListFrame(QFrame):
    # 待发布视频
    style = '''
        QTableWidget::item {
        border: none;
        outline: none;
        outline-style: none;
        font-size:14px;
        color:#333;
    }
    QAbstractItemView {
        outline: none;
    }
    QTableWidget::item:selected {
        background-color:#feffcc;
    }
    '''
    def __init__(self, parent=None):
        super(_videoListFrame, self).__init__()
        self.parent = parent
        
        self.setParent(self.parent)
        self.setObjectName("videoList")
        self.setStyleSheet(self.style)

        self.currentRow = -1
        self.allRow = 0
        
        self.setTables()
        self.setLayouts()

        self.page = 1
        self.limit = 100
        self.loading = 0

        #rowHeight = self.videoList.rowHeight(0)
        #rowHeight = 21 if rowHeight == 0 else rowHeight
        #tableHeight = self.videoList.height()
        #self.limit = int(tableHeight / rowHeight) - 1

    def setTables(self):
        self.videoList = _TableWidget(self)
        self.videoList.setMinimumWidth(self.width())
        self.videoList.setColumnCount(6)
        self.videoList.setHorizontalHeaderLabels(['ID','抖音号','视频标题','文件路径','大小','状态'])
        #self.videoList.horizontalHeader().setSectionResizeMode(QHeaderView.Fixed)
        self.videoList.horizontalHeader().setStretchLastSection(True)
        self.videoList.horizontalHeader().setVisible(True)
        self.videoList.horizontalHeader().setHighlightSections(False)
        self.videoList.verticalHeader().setVisible(False)
        self.videoList.resizeColumnToContents(True)
        
        self.videoList.setShowGrid(True)
        self.videoList.setAlternatingRowColors(True)

        self.videoList.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.videoList.setSelectionBehavior(QAbstractItemView.SelectRows)

        self.videoList.itemDoubleClicked.connect(self.wmplayer)

        self.videoList.setColumnWidth(0, 50)
        self.videoList.setColumnWidth(1, 200)
        self.videoList.setColumnWidth(2, 300)
        self.videoList.setColumnWidth(3, 400)

    def loadMore(self):
        if self.loading == 0:
            self.loading = 1
            keywords = self.titleEdit.text()
            allnum = self.parent.Db.countVideos(keywords=keywords)
            allpage = int(int(allnum + self.limit - 1) / self.limit)
            if allpage == 1:
                return True
            self.page = int(self.page) + 1
            if int(self.page) > allpage:
                self.page = allpage
            dbvideos = self.parent.Db.fetchVideos(limit=self.limit, page=self.page, keywords=keywords)
            self.addVideoList(dbvideos)
            self.loading = 0

    def setLayouts(self):
        label1 = QLabel('抖音号:')
        self.checkcombo = QComboCheckBox()
        self.checkcombo.setStyleSheet('''QComboBox{ width:120px; padding:2px; }
            QStandardItem{ line-height:150%; }''')
        label2 = QLabel('视频标题:')
        self.titleEdit = QLineEdit()
        self.titleEdit.setStyleSheet('QLineEdit{width:300px; padding:2px; font-size:14px}')
        self.searchButton = QPushButton('搜索')
        self.searchButton.setObjectName('search')
        self.searchButton.clicked.connect(self.pager)

        self.headerLayout = QHBoxLayout()
        self.headerLayout.addWidget(label1)
        self.headerLayout.addWidget(self.checkcombo)
        self.headerLayout.addWidget(label2)
        self.headerLayout.addWidget(self.titleEdit)
        self.headerLayout.addWidget(self.searchButton)
        self.headerLayout.addStretch(1)


        self.bodyLayout = QVBoxLayout()
        self.bodyLayout.setSpacing(0)
        self.bodyLayout.addWidget(self.videoList)

        footerLayout = QHBoxLayout()
        self.pagerInfo  = QLabel('')
        footerLayout.addWidget(self.pagerInfo)
        footerLayout.addStretch(1)
        footerLayout.setSpacing(7)
        self.firstButton = QPushButton()
        self.firstButton.setObjectName('firstpage')
        self.firstButton.setIcon(QIcon('./images/firstpage.png'))
        self.firstButton.setFixedSize(24,20)
        self.firstButton.clicked.connect(self.pager)
        self.pervButton = QPushButton()
        self.pervButton.setObjectName('pervpage')
        self.pervButton.setIcon(QIcon('./images/pervpage.png'))
        self.pervButton.setFixedSize(24,20)
        self.pervButton.clicked.connect(self.pager)
        self.curPage  = QLabel('1')

        self.nextButton = QPushButton()
        self.nextButton.setObjectName('nextpage')
        self.nextButton.setIcon(QIcon('./images/nextpage.png'))
        self.nextButton.setFixedSize(24,20)
        self.nextButton.clicked.connect(self.pager)
        self.lastButton = QPushButton()
        self.lastButton.setObjectName('lastpage')
        self.lastButton.setIcon(QIcon('./images/lastpage.png'))
        self.lastButton.setFixedSize(24,20)
        self.lastButton.clicked.connect(self.pager)

        '''
        footerLayout.addWidget(self.firstButton)
        footerLayout.addWidget(self.pervButton)
        footerLayout.addWidget(self.curPage)
        footerLayout.addWidget(self.nextButton)
        footerLayout.addWidget(self.lastButton)
        self.bodyLayout.addLayout(footerLayout)
        '''

        self.mainLayout = QVBoxLayout()
        self.mainLayout.addLayout(self.headerLayout)
        self.mainLayout.addLayout(self.bodyLayout)

        self.setLayout(self.mainLayout)

    def pager(self):
        # 手动翻页停用
        self.clear()
        action  = self.sender().objectName()
        keywords = ''
        if 'search' == action:
            keywords = self.titleEdit.text()
            self.page = 1

        allnum  = self.parent.Db.countVideos(keywords=keywords)
        allpage = int(int(allnum + self.limit - 1) / self.limit)

        if 'firstpage' == action:
            self.page = 1

        if 'pervpage' == action:
            self.page = int(self.page) - 1
            if int(self.page) < 1:
                self.page = 1

        if 'nextpage' == action:
            self.page = int(self.page) + 1
            if int(self.page) > allpage:
                self.page = allpage

        if 'lastpage' == action:
            self.page = allpage

        self.firstButton.setEnabled(True)
        self.pervButton.setEnabled(True)
        self.nextButton.setEnabled(True)
        self.lastButton.setEnabled(True)
        if self.page == 1:
            self.firstButton.setEnabled(False)
            self.pervButton.setEnabled(False)

        if self.page == allpage:
            self.nextButton.setEnabled(False)
            self.lastButton.setEnabled(False)
        

        self.curPage.setText('%s/%s' % (self.page, allpage))
        self.pagerInfo.setText('共 %s 条' % allnum)

        dbvideos = self.parent.Db.fetchVideos(limit = self.limit, page = self.page, keywords=keywords)
        self.addVideoList(dbvideos)


    #todo: 标题编辑和视频预览
    def wmplayer(self, index):
        row = index.row()
        try:
            filePath = self.videoList.item(row, 3).text()
            os.system('start "wmplayer" "%s"' % filePath)
        except Exception as e:
            pass

    def clear(self):
        self.videoList.clears(True)
        self.allRow = 0

    def clearComboItem(self):
        self.checkcombo.clear_items()

    def addComboItem(self, items):
        self.checkcombo.add_items(items)


    def addVideoItem(self, vid, userName, filePath, fileSize, title):
        self.videoList.setRowCount(self.allRow+1)
        
        idItem = QTableWidgetItem(str(vid))
        self.videoList.setItem(self.allRow, 0, idItem)

        userItem = QTableWidgetItem(userName)
        self.videoList.setItem(self.allRow, 1, userItem)

        titleItem = QTableWidgetItem(title)
        self.videoList.setItem(self.allRow, 2, titleItem)

        pathItem = QTableWidgetItem(filePath)
        self.videoList.setItem(self.allRow, 3, pathItem)

        sizeItem = QTableWidgetItem(fileSize)
        self.videoList.setItem(self.allRow, 4, sizeItem)

        stateItem = QTableWidgetItem('待发布')
        self.videoList.setItem(self.allRow, 5, stateItem)

        self.allRow += 1

    def addVideoList(self, items):
        for it in items:
            self.addVideoItem(it[0], it[2], it[5], it[6], it[7])

    def delVideos(self, vid = 0, dropAll = False):
        if int(vid) > 0:
            #只删除对应文件
            try:
                filePath = self.parent.Db.fetchOneVideos(vid)
                os.remove(filePath[5])
            except Exception as e:
                pass
            self.parent.Db.delVideos(vid = vid)
        if dropAll:
            #删除全部用户缓存文件
            dbusers = self.parent.Db.fetchUsers()
            for u in dbusers:
                try:
                    filePath = os.path.join(self.parent.absolutePath, 'cache', str(u[0]))
                    shutil.rmtree(filePath)
                except Exception as e:
                    pass
            self.parent.Db.delVideos(dropAll = True)


class _usersListFrame(QFrame):
    # 账号管理
    style = '''
        QTableWidget::item {
        border: none;
        outline: none;
        outline-style: none;
        font-size:14px;
        color:#333;
    }
    QAbstractItemView {
        outline: none;
    }
    QTableWidget::item:selected {
        background-color:#feffcc;
    }
    QTabWidget::pane{
        border: none;
    }
    QTabBar::tab {
        padding:3px 6px 3px 6px;
        min-width:80px; min-height:20px;
    }
    QTabBar::tab:selected {
        background-color:white;
        border:1px solid #999;
        border-bottom:none;
    }
    QListWidget::item {
        border: none;
        color:#333;
        border-bottom:1px solid #eee;
    }
    QListWidget::item:hover {
        background-color:#f2f6fb;
    }
    QListWidget::item:selected {
        background-color:#f2f2f2;
    }
    '''
    def __init__(self, parent=None):
        super(_usersListFrame, self).__init__()
        self.parent = parent

        self.setParent(self.parent)
        self.setObjectName("usersList")
        self.setStyleSheet(self.style)

        self.userItems = []
        self.currentRow = -1
        self.allRow = 0
        self.allRowpub = 0

        self.page = 1
        self.pagepub = 1
        self.limit = 100
        self.loading = 0
        
        self.setLists()
        self.setTables()
        self.setLayouts()

    def setLists(self):
        self.userList = _ListWidget(self)

    def setTables(self):
        self.videoList = _TableWidget(self)
        self.videoList.setMinimumWidth(self.width())
        self.videoList.setColumnCount(5)
        self.videoList.setHorizontalHeaderLabels(['ID','视频标题','文件路径','大小','状态'])
        self.videoList.horizontalHeader().setStretchLastSection(True)
        self.videoList.horizontalHeader().setVisible(True)
        self.videoList.horizontalHeader().setHighlightSections(False)
        self.videoList.verticalHeader().setVisible(False)
        self.videoList.resizeColumnToContents(True)
        
        self.videoList.setShowGrid(True)
        self.videoList.setAlternatingRowColors(True)

        self.videoList.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.videoList.setSelectionBehavior(QAbstractItemView.SelectRows)

        self.videoList.itemDoubleClicked.connect(self.wmplayer)

        self.videoList.setColumnWidth(0, 50)
        self.videoList.setColumnWidth(1, 300)
        self.videoList.setColumnWidth(2, 400)


        self.videoListpub = _TableWidget(self)
        self.videoListpub.setMinimumWidth(self.width())
        self.videoListpub.setColumnCount(5)
        self.videoListpub.setHorizontalHeaderLabels(['ID','视频标题','播放数','点赞数','上传时间'])
        self.videoListpub.horizontalHeader().setStretchLastSection(True)
        self.videoListpub.horizontalHeader().setVisible(True)
        self.videoListpub.horizontalHeader().setHighlightSections(False)
        self.videoListpub.verticalHeader().setVisible(False)
        self.videoListpub.resizeColumnToContents(True)
        
        self.videoListpub.setShowGrid(True)
        self.videoListpub.setAlternatingRowColors(True)

        self.videoListpub.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.videoListpub.setSelectionBehavior(QAbstractItemView.SelectRows)

        self.videoListpub.setColumnWidth(0, 50)
        self.videoListpub.setColumnWidth(1, 400)

    def setLayouts(self):
        self.mainLayout = QVBoxLayout()
        self.tabWidget = QTabWidget()
        self.tabWidget.addTab(self.videoList, '待发布视频')
        self.tabWidget.addTab(self.videoListpub, '已发布视频')
        self.userMoreLayout = QGridLayout()
        self.userMoreLayout.setSpacing(10)
        self.userMoreLayout.setColumnStretch(1,5)
        self.userMoreLayout.addWidget(self.userList, 1, 0)
        self.userMoreLayout.addWidget(self.tabWidget, 1, 1)
        self.mainLayout.addLayout(self.userMoreLayout)

        self.setLayout(self.mainLayout)

    #todo: 视频预览
    def wmplayer(self, index):
        row = index.row()
        try:
            filePath = self.videoList.item(row, 2).text()
            os.system('start "wmplayer" "%s"' % filePath)
        except Exception as e:
            pass

    def clears(self):
        self.videoList.clears(True)
        self.videoListpub.clears(True)
        self.allRow = 0
        self.allRowpub = 0

    def addUserItem(self, uid, phone, userId, userName, userAvatar=''):
        widget = QWidget()
        layout_main = QHBoxLayout()
        avatar = QLabel()  # 头像显示
        avatar.setFixedSize(32, 32)
        avatar.setScaledContents(True)
        if userAvatar is not '':
            try:
                pixmap = QPixmap()
                pixmap.loadFromData(requests.get(userAvatar).content)
                avatar.setPixmap(pixmap)
            except Exception as e:
                pass
        layout_main.addWidget(avatar)
        layout_main.addWidget(QLabel(userName + '\n' + phone))
        layout_main.addStretch(1)
        arrow = QLabel()
        maps = QPixmap(self.parent.absolutePath + '/images/right32.png').scaled(32, 32)
        arrow.setPixmap(maps)
        layout_main.addWidget(arrow)
        labelVal = QLabel(str(uid))
        labelVal.setObjectName('labelVal')
        labelVal.setVisible(False)
        layout_main.addWidget(labelVal)

        widget.setLayout(layout_main)
        item = QListWidgetItem()
        item.setSizeHint(QSize(200, 50))
        self.userList.addItem(item)
        self.userList.setItemWidget(item, widget)
        self.userList.items.append(uid)

    def viewVideoTable(self):
        widget = self.userList.itemWidget(self.userList.currentItem())
        self.curuid = widget.findChild(QLabel, 'labelVal').text()
        
        dbvideos = self.parent.Db.fetchVideos(self.curuid)
        self.parent.fetchVideospub(self.curuid)
        dbvideospub = self.parent.Db.fetchVideospub(self.curuid)
        self.clears()
        self.addVideoList(dbvideos)
        self.addVideoListpub(dbvideospub)

    def loadMore(self):
        curtab = self.tabWidget.currentIndex()
        if self.loading == 0:
            self.loading = 1
            if curtab == 0:
                allnum = self.parent.Db.countVideos()
                allpage = int(int(allnum + self.limit - 1) / self.limit)
                if allpage == 1:
                    return True
                self.page = int(self.page) + 1
                if int(self.page) > allpage:
                    self.page = allpage
                dbvideos = self.parent.Db.fetchVideos(userId=self.curuid, limit=self.limit, page=self.page)
                self.addVideoList(dbvideos)
            else:
                allnum = self.parent.Db.countVideospub()
                allpage = int(int(allnum + self.limit - 1) / self.limit)
                if allpage == 1:
                    return True
                self.pagepub = int(self.pagepub) + 1
                if int(self.pagepub) > allpage:
                    self.pagepub = allpage
                dbvideos = self.parent.Db.fetchVideospub(userId=self.curuid, limit=self.limit, page=self.pagepub)
                self.addVideoListpub(dbvideos)
            self.loading = 0

    def addUserList(self, items):
        self.tdUseradd = ThreadUseradd(items)
        self.tdUseradd._signal.connect(self.addUserItem)
        self.tdUseradd.start()

    def delUsers(self, uid):
        #删除用户相关缓存文件
        try:
            filePath = os.path.join(self.parent.absolutePath, 'cache', str(uid))
            shutil.rmtree(filePath)
        except Exception as e:
            pass
        #删除相关记录
        self.parent.Db.delUsers(uid)
        self.parent.Db.delVideos(userId = uid)
        self.parent.Db.delVideospub(userId = uid)
        self.viewVideoTable()

    def addVideoItem(self, vid, userName, filePath, fileSize, title):
        self.videoList.setRowCount(self.allRow+1)
        idItem = QTableWidgetItem(str(vid))
        self.videoList.setItem(self.allRow, 0, idItem)

        titleItem = QTableWidgetItem(title)
        self.videoList.setItem(self.allRow, 1, titleItem)

        pathItem = QTableWidgetItem(filePath)
        self.videoList.setItem(self.allRow, 2, pathItem)

        sizeItem = QTableWidgetItem(fileSize)
        self.videoList.setItem(self.allRow, 3, sizeItem)

        stateItem = QTableWidgetItem('待发布')
        self.videoList.setItem(self.allRow, 4, stateItem)

        self.allRow += 1

    def addVideoList(self, items):
        for it in items:
            self.addVideoItem(it[0], it[2], it[5], it[6], it[7])


    def addVideoItempub(self, vid, title, playCount, likeCount, uploadTime):
        self.videoListpub.setRowCount(self.allRowpub+1)
        idItem = QTableWidgetItem(str(vid))
        self.videoListpub.setItem(self.allRowpub, 0, idItem)

        titleItem = QTableWidgetItem(title)
        self.videoListpub.setItem(self.allRowpub, 1, titleItem)

        playItem = QTableWidgetItem(playCount)
        self.videoListpub.setItem(self.allRowpub, 2, playItem)

        likeItem = QTableWidgetItem(likeCount)
        self.videoListpub.setItem(self.allRowpub, 3, likeItem)

        timeItem = QTableWidgetItem(uploadTime)
        self.videoListpub.setItem(self.allRowpub, 4, timeItem)
        
        self.allRowpub += 1

    def addVideoListpub(self, items):
        if items is False:
            return True
        for it in items:
            self.addVideoItempub(it[0], it[3], str(it[6]), str(it[7]), it[5])

    def delVideos(self, vid = 0, dropAll = False):
        if int(vid) > 0:
            #只删除对应文件
            try:
                filePath = self.parent.Db.fetchOneVideos(vid)
                os.remove(filePath[5])
            except Exception as e:
                pass
            self.parent.Db.delVideos(vid = vid)
        if dropAll:
            #删除指定用户缓存文件
            try:
                filePath = os.path.join(self.parent.absolutePath, 'cache', str(self.curuid))
                shutil.rmtree(filePath)
            except Exception as e:
                pass
            self.parent.Db.delVideos(userId = self.curuid)


class ThreadUseradd(QThread):
    _signal = pyqtSignal(int, str, str, str, str)

    def __init__(self, items=''):
        super().__init__()
        self._items = items

    def run(self):
        for it in self._items:
            self._signal.emit(it[0], it[1], it[2], it[3], it[4])
            time.sleep(0.1)


class _TableWidget(QTableWidget):

    def __init__(self, parent=None):
        super(_TableWidget, self).__init__()
        self.scrollval = 0
        self.parent = parent
        self.items = []
        self.setActions()

    def setActions(self):
        self.actionClear = QAction(QIcon('./images/clear.png'), '清空', self)
        self.actionClear.triggered.connect(self.clears)

        self.actionRemove = QAction(QIcon('./images/remove.png'), '删除', self)
        self.actionRemove.triggered.connect(self.remove)

    def wheelEvent(self, event):
        # 滚动条到底继续加载
        r = self.rowHeight(0)
        r = 30 if r == 0 else r
        y = self.verticalScrollBar().value()
        h = int((self.rowCount() * r - self.height()) / 20)

        if y >= h and y > 0:
            self.parent.loadMore()

        super(_TableWidget, self).wheelEvent(event)

    def clears(self, sysAction = False):
        if sysAction:
            # 系统清空
            self.setRowCount(0)
            self.clearContents()
            self.items = []
            self.parent.allRow = 0
        else:
            # 用户手动删除
            reply = QMessageBox.warning(self, "删除", "删除后不可恢复，确认要全部删除吗？", QMessageBox.Yes | QMessageBox.No)
            if reply == QMessageBox.Yes:
                self.setRowCount(0)
                self.clearContents()
                self.items = []
                self.parent.allRow = 0
                # 删除全部视频 已发布未发布区分
                # pwidgetName = self.parent.objectName()
                self.parent.delVideos(dropAll = True)

    def remove(self):
        row = self.currentRow()
        vid = self.item(row, 0).text()
        reply = QMessageBox.question(self, "删除", "删除后不可恢复，确认要删除吗？", QMessageBox.Yes | QMessageBox.No)
        if reply == QMessageBox.Yes:
            self.removeRow(row)
            self.parent.delVideos(vid = vid)
            self.parent.allRow -= 1

    def contextMenuEvent(self, event):
        item = self.itemAt(self.mapFromGlobal(QCursor.pos()))
        self.menu = QMenu(self)

        if not item:
            self.menu.addAction(self.actionClear)
        else:
            self.menu.addAction(self.actionRemove)
            self.menu.addAction(self.actionClear)

        self.menu.exec_(QCursor.pos())



class _ListWidget(QListWidget):

    def __init__(self,parent=None):
        super(_ListWidget, self).__init__()
        self.parent = parent
        self.items = []
        self.setActions()
        self.itemClicked.connect(self.parent.viewVideoTable)

    def setActions(self):
        self.actionRemove = QAction(QIcon('./images/remove.png'), '删除', self)
        self.actionRemove.triggered.connect(self.remove)

    def clears(self):
        for i in range(0, self.count()):
            self.takeItem(i)
        self.items = []
        self.parent.allRow = 0


    def remove(self):
        # 找到当前ID
        widget = self.itemWidget(self.currentItem())
        uid = widget.findChild(QLabel, 'labelVal').text()
        row = self.currentRow()

        reply = QMessageBox.question(self, "删除", "删除后不可恢复，确认要删除吗？", QMessageBox.Yes | QMessageBox.No)
        if reply == QMessageBox.Yes:
            self.takeItem(row)
            self.parent.delUsers(uid)
            self.parent.allRow -= 1

    # 事件。
    def contextMenuEvent(self, event):
        item = self.itemAt(self.mapFromGlobal(QCursor.pos()))
        self.menu = QMenu(self)

        if item:
            self.menu.addAction(self.actionRemove)

        self.menu.exec_(QCursor.pos())


class _publishedFrame(QFrame):
    style = '''
    QLabel{margin:50px 0 50px 0; font-size:14px}
    QProgressBar{ height: 2px; width:100%; }
    QTextBrowser{ font-size:14px;}
    '''
    def __init__(self, parent=None):
        super(_publishedFrame, self).__init__()
        self.parent = parent

        self.setParent(self.parent)
        self.setObjectName("published")
        self.setStyleSheet(self.style)
        self.setLayouts()

    def showtop(self):
        self.label.show()
        self.toast.show()
        self.stopbtn.show()

    def hidetop(self):
        self.label.hide()
        #self.toast.hide()
        self.stopbtn.hide()

    def setLayouts(self):
        self.label = QLabel(self)
        self.label.setAlignment(Qt.AlignRight)
        self.movie = QMovie(self.parent.absolutePath + '/images/refresh.gif')
        self.label.setMovie(self.movie)
        self.movie.start()

        self.toast = QLabel()
        self.toast.setAlignment(Qt.AlignLeft)
        self.toast.setStyleSheet('QLabel{ margin-top:53px; margin-left:20px;}')
        self.toast.setFixedWidth(self.parent.width() / 2)

        self.stopbtn = QPushButton('暂 停')
        self.stopbtn.setFixedSize(70, 25)
        self.stopbtn.setIcon(QIcon(self.parent.absolutePath + '/images/pause.png'))
        self.stopbtn.clicked.connect(self.parent.publishStop)
        self.holder = QLabel()
        self.holder.setStyleSheet('QLabel{ margin-top:55px;}')

        self.topLayout = QHBoxLayout()
        self.topLayout.addWidget(self.label)
        self.topLayout.addWidget(self.toast)
        self.topLayout.addWidget(self.stopbtn)
        self.topLayout.addWidget(self.holder)
        '''
        self.topLayout.setStretchFactor(self.label, 1)
        self.topLayout.setStretchFactor(self.toast, 7)
        self.topLayout.setStretchFactor(self.stopbtn, 1)
        self.topLayout.setStretchFactor(self.holder, 1)
        '''
        self.loger = QTextBrowser()

        self.mainLayout = QVBoxLayout()
        self.mainLayout.addLayout(self.topLayout)
        self.mainLayout.addWidget(self.loger)
        self.setLayout(self.mainLayout)

    def printmsg(self, msg):
        self.loger.append(msg)
        self.loger.moveCursor(self.loger.textCursor().End)
        time.sleep(0.2)

